/*
同步：函数调用后，主程序等待着函数返回才会继续往下运行。
异步：函数调用后，主程序不等待函数返回就继续往下运行。
回调函数：异步情况下，函数执行完调用callback函数告知主程序子函数执行完毕。
阻塞：函数调用后，由于 I/O 等操作导致了 CPU 暂停执行本段程序。
非阻塞：函数调用后，CPU 不会因为此次调用而被切换去执行其他进程。
多线程：进程中包含多个线程，线程可以并行执行不同的任务。
并发和异步导致线程间资源无序竞争，线程同步通过锁来消除这种缺陷，实现线程正确有序共享数据。
锁Lock：互斥量和条件变量的组合。
互斥锁/互斥量Mutex：一次只允许一个线程访问共享资源。
条件变量Condition Variable：线程等待某个条件发生。必须和互斥锁一起使用。
读写锁ReadWrite Lock：允许多个线程同时读取共享资源，但只允许一个线程写入。
死锁Deadlock：两个或多个线程互相等待对方释放资源。
‌导致死锁的四个必要条件包括互斥条件、请求和保持条件、不可剥夺条件和环路等待条件‌。‌

    ‌互斥条件‌：至少有一个资源必须属于非共享模式，即一次只能被一个进程使用。如果其他进程申请使用该资源，必须等到该资源被释放。
    ‌请求和保持条件‌：一个进程已经持有一个或多个资源，同时又请求其他资源，而这些资源被其他进程占用。此时，该进程处于阻塞状态，但不会释放它已经持有的资源。
    ‌不可剥夺条件‌：进程已获得的资源在未使用完之前，不能被剥夺，只能在使用完后由自己释放。
    ‌环路等待条件‌：在发生死锁时，必然存在一个进程——资源的环形链，即若干进程之间形成一种头尾相接的环形等待资源关系。

死锁的预防策略：破坏四个必要条件之一

    ‌破坏互斥条件‌：在某些情况下，可以通过技术手段将独占资源改为共享资源。例如，使用SPOOLing技术管理打印机资源。
    ‌破坏请求和保持条件‌：采用静态分配策略，即一次性分配所有需要的资源。
    ‌破坏不可剥夺条件‌：允许强制释放资源，尽管这可能涉及复杂的资源恢复问题。
    ‌破坏环路等待条件‌：通过资源顺序分配法，对资源进行编号，确保进程按顺序申请资源。


避免死锁的方法：避免嵌套锁、按照固定顺序加锁、使用超时机制、死锁检测算法。
‌死锁避免算法‌：如银行家算法，通过动态判断系统资源分配的安全性来避免死锁
银行家算法：
    系统中有n个进程，m类资源，每个进程最大资源需求量Max，已分配资源量Allocation，还需要资源量Need，系统资源量Available。
    当一个进程请求资源时，系统判断是否能满足其需求，如果满足则分配资源，否则让进程等待。如果进程执行完毕，释放资源，系统回收资源。
    如果系统资源不足，进程等待。如果系统资源充足，但分配后可能导致死锁，则不分配资源。
死锁的检测和解除：通过系统监控资源的分配情况来检测死锁，解除死锁：

    ‌资源剥夺法‌：强制剥夺某些进程的资源，将其分配给其他需要这些资源的进程。
    ‌进程回退法‌：让某些进程回退到某个检查点，释放所有占有的资源，然后重新执行。


*/
#include <mutex>
#include <condition_variable>
#include <atomic>//原子操作
#include <thread>
std::mutex mtx;// 互斥量
std::condition_variable cv;// 条件变量
bool ready = false;

void workerThread()
{
    std::unique_lock<std::mutex> lk(mtx);//unique_lock比lock_guard更灵活,可以转移所有权和手动解锁
    cv.wait(lk, []
            { return ready; }); // 等待条件
    // 当条件满足时执行工作
}

void mainThread()
{
    {
        std::lock_guard<std::mutex> lk(mtx);
        // 准备数据
        ready = true;
    } // 离开作用域时解锁
    cv.notify_one(); // 通知一个等待的线程
}
/*原子操作（Atomic Operations）:
确保对共享数据的访问是不可分割的，要么全部执行成功，要么全部不执行。
*/
std::atomic<int> count(0);

void increment()
{
    count.fetch_add(1, std::memory_order_relaxed);
}

int main()
{
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    return count; // 应返回2
}